package easy.trace.plugin.mybatis;

import com.alibaba.fastjson.JSON;
import easy.trace.core.dto.MySQLEvent;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDate;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;

/**
 * @author easy
 */
public class MybatisContextParser {
    private static final Logger log = LoggerFactory.getLogger(MybatisContextParser.class);

    private static final Pattern DB_IP_PORT_PATTERN = Pattern.compile("jdbc:mysql://(?<ipport>[a-zA-Z0-9.]+:[0-9]+)/(?<database>[a-zA-Z]\\w+)?.+");


    /**
     * 参数解析
     *
     * @param obj
     * @return
     */
    private static String getParameterValue(Object obj) {
        if (obj instanceof String) {
            return "'" + obj.toString() + "'";
        } else if (obj instanceof Date) {
            return LocalDate.now().toString();
        } else {
            if (obj != null) {
                return obj.toString();
            } else {
                return "";
            }

        }
    }

    /**
     * 解析sql
     *
     * @param configuration
     * @param boundSql
     * @return
     */
    public static String showSql(Configuration configuration, BoundSql boundSql) {
        Object parameterObject = boundSql.getParameterObject();
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
        if (parameterMappings.size() > 0 && parameterObject != null) {
            TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
            if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                sql = sql.replaceFirst("\\?", getParameterValue(parameterObject));

            } else {
                MetaObject metaObject = configuration.newMetaObject(parameterObject);
                for (ParameterMapping parameterMapping : parameterMappings) {
                    String propertyName = parameterMapping.getProperty();
                    if (metaObject.hasGetter(propertyName)) {
                        Object obj = metaObject.getValue(propertyName);
                        sql = sql.replaceFirst("\\?", getParameterValue(obj));
                    } else if (boundSql.hasAdditionalParameter(propertyName)) {
                        Object obj = boundSql.getAdditionalParameter(propertyName);
                        sql = sql.replaceFirst("\\?", getParameterValue(obj));
                    }
                }
            }
        }
        return sql;
    }

    public static MySQLEvent showSqlEvent(Object parameter, MappedStatement mappedStatement) {
        //得到sql语句
        BoundSql boundSql = mappedStatement.getBoundSql(parameter);
        Configuration configuration = mappedStatement.getConfiguration();

        final String sql = showSql(configuration, boundSql);

        final String commandType = showCommandType(mappedStatement);

        MySQLEvent event = new MySQLEvent();
        event.setSql(sql);
        event.setSqlCommandType(commandType);
        return event;
    }

    public static String getEventData(Object parameter, MappedStatement mappedStatement) {
        //得到sql语句
        BoundSql boundSql = mappedStatement.getBoundSql(parameter);
        Configuration configuration = mappedStatement.getConfiguration();

        final String sql = showSql(configuration, boundSql);

        final String commandType = showCommandType(mappedStatement);

        MySQLEvent event = new MySQLEvent();
        event.setSql(sql);
        event.setSqlCommandType(commandType);
        return JSON.toJSONString(event);
    }

    private static String showCommandType(MappedStatement mappedStatement) {
        if (Objects.isNull(mappedStatement)) {
            return "default";
        }
        try {
            return mappedStatement.getSqlCommandType().name().toLowerCase();
        } catch (Exception e) {
            log.error(e.getLocalizedMessage());
        }
        return "default";
    }

    public static String getServiceMapper(MappedStatement mappedStatement) {
        if (Objects.isNull(mappedStatement)) {
            return "default";
        }
        try {
            String[] strArr = mappedStatement.getId().split("\\.");
            return strArr[strArr.length - 2];
        } catch (Exception e) {
            log.error(e.getLocalizedMessage());
        }
        return mappedStatement.getId();
    }

    public static String getMethodMapper(MappedStatement mappedStatement) {
        if (Objects.isNull(mappedStatement)) {
            return "default";
        }
        try {
            String[] strArr = mappedStatement.getId().split("\\.");
            return strArr[strArr.length - 1];
        } catch (Exception e) {
            log.error(e.getLocalizedMessage());
        }
        return mappedStatement.getId();
    }
}
